package com.itheima.activiti.service.activiti.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.activiti.common.WorkflowException;
import com.itheima.activiti.dragram.ActivitiProcessDiagramGenerator;
import com.itheima.activiti.dto.activiti.ProcessDefinitionDTO;
import com.itheima.activiti.service.activiti.DeployService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DeployServiceImpl implements DeployService {

    @Autowired
    private RepositoryService repositoryService;

    @Override
    public Deployment deploy(String id) {
        Model model = repositoryService.getModel(id);
        byte[] contentByte = repositoryService.getModelEditorSource(id);

        if (contentByte == null) {
            throw new WorkflowException("未找到流程内容");
        }
        Deployment deployment = null;
        try {
            deployment = repositoryService
                    .createDeployment()
                    .key(model.getKey())
                    .name(model.getName())
                    .addString(model.getName() + ".bpmn20.xml", new String(contentByte))
                    .deploy();

        } catch (Exception e) {
            log.error("流程部署异常", e);
            throw new WorkflowException("部署异常");
        }

        if (deployment == null) {
            throw new WorkflowException("部署失败");
        }
        return deployment;
    }

    @Override
    public void removeByIds(List<String> ids) {
        try {
            for (String id : ids) {
                repositoryService.deleteDeployment(id);
            }
        } catch (Exception e) {
            log.error("删除流程异常", e);
            throw new WorkflowException("删除流程异常");
        }
    }

    @Override
    public Page<ProcessDefinitionDTO> page(ProcessDefinitionDTO processDefinitionDTO, int page, int pageSize) {
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
        if (StringUtils.isNotBlank(processDefinitionDTO.getDeploymentId())) {
            query.deploymentId(processDefinitionDTO.getDeploymentId());
        }
        if (StringUtils.isNotBlank(processDefinitionDTO.getId())) {
            query.processDefinitionId(processDefinitionDTO.getId());
        }
        if (StringUtils.isNotBlank(processDefinitionDTO.getKey())) {
            query.processDefinitionKey(processDefinitionDTO.getKey());
        }
        if (StringUtils.isNotBlank(processDefinitionDTO.getName())) {
            query.processDefinitionNameLike(processDefinitionDTO.getName());
        }
        List<ProcessDefinition> list = query.listPage((page - 1) * pageSize, pageSize);
        List<ProcessDefinitionDTO> processDefinitionDTOList = null;
        if (list != null && list.size() > 0) {
            processDefinitionDTOList = list.stream().map(item -> {
                ProcessDefinitionDTO dto = new ProcessDefinitionDTO();
                BeanUtils.copyProperties(item, dto);
                Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(item.getDeploymentId()).singleResult();
                dto.setDeploymentTime(LocalDateTime.ofInstant(deployment.getDeploymentTime().toInstant(), ZoneId.systemDefault()));
                return dto;
            }).collect(Collectors.toList());
        }
        long total = query.count();

        Page<ProcessDefinitionDTO> pageResult = new Page(page, pageSize, total);
        pageResult.setRecords(processDefinitionDTOList);
        return pageResult;
    }

    @Override
    public InputStream getResourceAsStream(String deploymentId, String resourceName) {
        InputStream resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resourceName);

        return resourceAsStream;
    }

    @Override
    public void active(String id) {
        repositoryService.activateProcessDefinitionById(id, true, null);
    }

    @Override
    public void suspend(String id) {
        repositoryService.suspendProcessDefinitionById(id, true, null);
    }

    @Override
    public InputStream svg(String deploymentId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());

        ProcessDiagramGenerator diagramGenerator = new ActivitiProcessDiagramGenerator();

        InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, new ArrayList<>());

        return inputStream;
    }
}
